//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using OpenLS.Core.Serialization;
using OpenLS.Spreadsheet;
using OpenLS.Spreadsheet.StandardAddIn;
using OpenLS.Spreadsheet.StandardAddIn.Statistics;

namespace OpenLS.Spreadsheet.Pivot
{
    internal class DataField : IOfficeXmlSerializable
    {
        private string _name;
        private int _fld;
        private DataConsolidateFunction _subtotal;
        private ShowDataAs _showDataAs;
        private int _baseField;
        private int _baseItem;
        private uint? numFmtId;
        private ExtensionList _extLst;

        internal int BaseField
        {
            get { return _baseField; }
        }

        internal ShowDataAs ShowDataAs
        {
            get { return _showDataAs; }
        }

        internal int FieldIndex
        {
            get { return _fld; }
        }

        internal Func<IEnumerable<object>, object> GetSubtotalFunction()
        {
            switch (this._subtotal)
            {
                case DataConsolidateFunction.Average:
                    return a => Statistician.Mean(Enumerable.OfType<double>(a));
                    case DataConsolidateFunction.Count:
                    return a => Enumerable.Count(a);
                    case DataConsolidateFunction.CountNumbers:
                    return a => Enumerable.Count(Enumerable.OfType<double>(a));
                    case DataConsolidateFunction.Maximum:
                    return a => Enumerable.Max(Enumerable.OfType<double>(a));
                    case DataConsolidateFunction.Minimum:
                    return a => Enumerable.Min(Enumerable.OfType<double>(a));
                    case DataConsolidateFunction.Product:
                    return a => Enumerable.Aggregate(Enumerable.OfType<double>(a), 1.0, (x, y) => x*y);
                    case DataConsolidateFunction.StandardDeviation:
                    return a => StatisticalFunctions.StDev(Enumerable.ToArray(Enumerable.OfType<double>(a)));
                    case DataConsolidateFunction.StandardDeviationPopulation:
                    return a => StatisticalFunctions.StDevP(Enumerable.ToArray(Enumerable.OfType<double>(a)));
                    case DataConsolidateFunction.Sum:
                    return a => Enumerable.Sum(Enumerable.OfType<double>(a));
                    case DataConsolidateFunction.Variance:
                    return a => Statistician.Variance(Enumerable.OfType<double>(a));
                    case DataConsolidateFunction.VariancePopulation:
                    return a => StatisticalFunctions.VarP(Enumerable.ToArray(Enumerable.OfType<double>(a)));
                    default: throw new NotSupportedException();
            }
        }

        public void ReadXml(ReadContext context)
        {
            using (var c = context.Read("dataField"))
            {
                _name = c.GetOptionalString("name");
                _fld = c.GetUIntegerAsInteger("fld");
                _subtotal = c.GetOptionalEnum<DataConsolidateFunction>("subtotal", DataConsolidateFunction.Sum);
                _showDataAs = c.GetOptionalEnum<ShowDataAs>("showDataAs", ShowDataAs.Normal);
                _baseField = c.GetOptionalInteger("baseField", -1);
                _baseItem = c.GetOptionalInteger("baseItem", 1048832);
                numFmtId = c.GetOptionalUInteger("numFmtId");
                this._extLst = c.ReadOptionalElement<ExtensionList>("extLst");
            }
        }

        public void WriteXml(WriteContext context)
        {
            using (var c = context.Write("dataField"))
            {
                c.SetOptionalString("name", _name);
                c.SetUIntegerAsInteger("fld", _fld);
                c.SetOptionalEnum<DataConsolidateFunction>("subtotal", _subtotal, DataConsolidateFunction.Sum);
                c.SetOptionalEnum<ShowDataAs>("showDataAs", ShowDataAs, ShowDataAs.Normal);
                c.SetOptionalInteger("baseField", BaseField, -1);
                c.SetOptionalInteger("baseItem", _baseItem, 1048832);
                c.SetOptionalUInteger("numFmtId", numFmtId);
                c.WriteOptionalElement(this._extLst);
            }
        }
    }
}